#include "source.h"

#include "item.h"

#include "namespace.h"
#include "uniquename.h"

#include "pricegrabber.h"
#include "urlutils.h"

#include <assert.h>

Source::Source(
    NameSpace *nameSpace
,   const QString &name
,   const int price
,   const QUrl &url)
:   QObject(NULL)
,   m_ignored(false)
,   m_price(price)
,   m_previousPrice(INVALID_PRICE)
,   m_quantity(1)
,   m_url(url)
,   m_priceGrabber(NULL)
{
    m_name = new UniqueName(name.toStdString());
    m_name->setNameSpace(nameSpace);
}

Source::~Source()
{
    delete m_name;
    delete m_priceGrabber;
}

void Source::setName(const QString &name)
{
    if(this->name() == name)
        return;

    m_name->setName(name.toStdString());

    emit nameChanged(this->name());
    emit modified();
}

const QString Source::name() const
{
    return QString::fromStdString(m_name->name());
}

void Source::setPrice(const int price)
{
    if(m_price == price)
        return;

    m_previousPrice = m_price;
    m_price = price;

    emit priceChanged(this->price());
    emit modified();
}

const int Source::price() const
{
    if(isValid())
        return m_price;

    return -1;
}

void Source::setUrl(const QUrl &url)
{
    if(m_url == url)
        return;

    m_url = url;

    emit urlChanged(this->url());
    emit modified();
}

const QUrl &Source::url() const
{
    return m_url;
}

void Source::setQuantity(const uint quantity)
{
    if(quantity == m_quantity)
        return;

    m_quantity = quantity;

    emit quantityChanged(m_quantity);
    emit modified();
}

const uint Source::quantity() const
{
    return m_quantity;
}

void Source::setIgnored(const bool ignored)
{
    if(ignored == m_ignored)
        return;

    m_ignored = ignored;

    emit ignoreStateChanged(m_ignored);
    emit modified();
}

const bool Source::ignored() const
{
    return m_ignored;
}

const bool Source::isValid() const
{
    return m_price != INVALID_PRICE;
}

const QString &Source::error() const
{
    return m_error;
}

const QString Source::host(const QUrl &url)
{
    return url.host().toLower();;
}

const int Source::differenceToPreviousPrice() const
{
    if(m_previousPrice == INVALID_PRICE || !isValid())
        return 0;

    return m_price - m_previousPrice;
}

void Source::priceGrabberSucceeded(int price)
{
    assert(m_priceGrabber);

    delete m_priceGrabber;
    m_priceGrabber = NULL;

    setPrice(price);

    emit updated(true);
}

void Source::priceGrabberFailed(QString error)
{
    assert(m_priceGrabber);

    delete m_priceGrabber;
    m_priceGrabber = NULL;

    m_error = error;

    emit updated(false);
}

void Source::update()
{
    if(isUpdating())
        return;

    if(!isValidUrl(url()))
    {
        emit updated(true);
        return;
    }

    m_priceGrabber = PriceGrabber::queue(url());

    connect(m_priceGrabber, SIGNAL(grabSucceeded(int))
        , this, SLOT(priceGrabberSucceeded(int)));
    connect(m_priceGrabber, SIGNAL(grabFailed(QString))
        , this, SLOT(priceGrabberFailed(QString)));


    emit updateStarted();

    PriceGrabber::triggerQueue();
}

void Source::cancel()
{
    if(!isUpdating())
        return;

    delete m_priceGrabber;
    m_priceGrabber = NULL;

    emit canceled();
}

const bool Source::isUpdating() const
{
    return m_priceGrabber;
}
